
#include "lib_drm.h"

#include "../lib_mpp/lib_mpp.h"
#include "../lib_ffmpeg/lib_ffmpeg.h"

#define CODEC_ALIGN(x, a)   (((x)+(a)-1)&~((a)-1))

static drm_para_t drm_p;

extern f_para_t f_p;

int lib_drm_edp_show(char * buff, int w, int h, int size)
{

	memcpy(drm_p.drm_edp.fb_vaddr,buff,size);


	drmModeSetPlane(drm_p.drm_fd, 
					drm_p.drm_plane_id[1], 
					drm_p.drm_crtc_id[1], 
					drm_p.drm_edp.fb_id, 
					0,0,0,
					drm_p.drm_edp.fb_w, 
					drm_p.drm_edp.fb_h,
					0 << 16, 0 << 16, 
					drm_p.drm_edp.fb_w << 16,
					drm_p.drm_edp.fb_h << 16);

	return 0;
}

int lib_drm_hdmi_show(char * buff, int w, int h, int size)
{
	memcpy(drm_p.drm_hdmi.fb_vaddr,buff,size);

	drmModeSetPlane(drm_p.drm_fd, 
					drm_p.drm_plane_id[0], 
					drm_p.drm_crtc_id[0], 
					drm_p.drm_hdmi.fb_id, 
					0,0,0,
					drm_p.drm_hdmi.fb_w, 
					drm_p.drm_hdmi.fb_h,
					0 << 16, 0 << 16, 
					drm_p.drm_hdmi.fb_w << 16,
					drm_p.drm_hdmi.fb_h << 16);


   return 0;
}

int lib_drm_hdmi_nv12_show(char * buff, int w, int h, int size)
{
	int ret = -1;
	int x = 0;
	int y = 0;
	int swap_w = 0;
	int swap_h = 0;
	//***********************************************************
    int fd  = -1;
	int err = -1;
	struct sp_bo *bo;
    uint32_t handles[4], pitches[4], offsets[4];
	//***********************************************************

	char * src_data = NULL;
	char * cvt_data = NULL;
	char * dst_data = NULL;
	
	MppBuffer src_buffer = NULL;
	MppBuffer cvt_buffer = NULL;
	MppBuffer dst_buffer = NULL;

	//***********************************************************
	log_n("w=%d\n",w);
	log_n("h=%d\n",h);
	//***********************************************************

	mpp_buffer_get(NULL, &src_buffer, size); //申请内存
	src_data = mpp_buffer_get_ptr(src_buffer);
	memcpy(src_data,buff,size);
	//***********************************************************

	mpp_buffer_get(NULL, &cvt_buffer, size); //申请内存
	cvt_data = mpp_buffer_get_ptr(cvt_buffer);

	ret = rga_rgbdata_cvtcolor(src_data,cvt_data,w,h);
	//***********************************************************
	mpp_buffer_get(NULL, &dst_buffer, size); //申请内存
	dst_data = mpp_buffer_get_ptr(dst_buffer);

	ret = rga_nv12data_rotation(cvt_data,dst_data,w,h);
	//***********************************************************
	if(ret != 0)
	{
		if(dst_buffer){
			mpp_buffer_put(dst_buffer);
			dst_buffer = NULL;
		}
		if(cvt_buffer){
			mpp_buffer_put(cvt_buffer);
			cvt_buffer = NULL;
		}
		
		if(src_buffer){
			mpp_buffer_put(src_buffer);
			src_buffer = NULL;
		}

		return -1;
	}
	//***********************************************************
	swap_w = h;
	swap_h = w;

	log_n("swap_w=%d\n",swap_w);
	log_n("swap_h=%d\n",swap_h);
	//***********************************************************

	fd = mpp_buffer_get_fd(dst_buffer);
	//***********************************************************

    bo = (struct sp_bo *)calloc(1, sizeof(struct sp_bo));
    if (!bo) {
        log_n("failed to calloc bo.\n");
        return -2;
    }


    drmPrimeFDToHandle(drm_p.drm_fd, fd, &bo->handle);
    bo->dev    = drm_p.drm_dev;
    bo->width  = swap_w;
    bo->height = swap_h;
    bo->depth  = 16;
    bo->bpp    = 32;
    bo->format = DRM_FORMAT_NV12;
    bo->flags  = 1;

    handles[0] = bo->handle;
    pitches[0] = swap_w;
    offsets[0] = 0;
    handles[1] = bo->handle;
    pitches[1] = swap_w;
    offsets[1] = swap_w * swap_h;
	
    ret = drmModeAddFB2(drm_p.drm_fd, bo->width, bo->height,bo->format, 
						handles, pitches, offsets,&bo->fb_id, bo->flags);
    if (ret != 0) {
        log_n("failed to exec drmModeAddFb2.\n");
        return -3;
    }

	x = 0;
	y = 0;
	w = swap_w;
	h = swap_h;
	//*******************************************************************************
	log_n("x=%d\n",x);
	log_n("y=%d\n",y);
	log_n("w=%d\n",w);
	log_n("h=%d\n",h);
	//*******************************************************************************

    ret = drmModeSetPlane(drm_p.drm_fd, drm_p.drm_hdmi_show->plane->plane_id,
                          drm_p.drm_dev->crtcs->crtc->crtc_id, bo->fb_id, 0,
                          x, y,   // display x, y
                          w, 	  //1920,//mCrtc->crtc->mode.hdisplay, // display width
                          h,      // 1080,//mCrtc->crtc->mode.vdisplay, // display height
                          0, 0, bo->width << 16, bo->height << 16);
    if (ret) {
        log_n("failed to exec drmModeSetPlane.\n");
        return -3;
    }

    if(drm_p.drm_hdmi_show->bo) 
	{
        if(drm_p.drm_hdmi_show->bo->fb_id) 
		{
            ret = drmModeRmFB(drm_p.drm_fd, drm_p.drm_hdmi_show->bo->fb_id);
            if(ret)
                log_n("failed to exec drmModeRmFB.\n");
        }
		
        if(drm_p.drm_hdmi_show->bo->handle) 
		{
            struct drm_gem_close req = 
			{
                    .handle = drm_p.drm_hdmi_show->bo->handle,
            };

            drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
        }
        free(drm_p.drm_hdmi_show->bo);
    }
    drm_p.drm_hdmi_show->bo = bo;
	//*******************************************************************************

	if(dst_buffer){
		mpp_buffer_put(dst_buffer);
		dst_buffer = NULL;
	}
	if(cvt_buffer){
		mpp_buffer_put(cvt_buffer);
		cvt_buffer = NULL;
	}

	if(src_buffer){
		mpp_buffer_put(src_buffer);
		src_buffer = NULL;
	}

	//*******************************************************************************

    return 0;
}

int lib_drm_edp_fill(uint32_t x, uint32_t y, uint32_t w,uint32_t h, uint32_t color)
{
	uint8_t a = 0;
	uint8_t r = 0;
	uint8_t g = 0;
	uint8_t b = 0;

	uint32_t i = 0;
	uint32_t j = 0;

	uint32_t xmax = x + w;
	uint32_t ymax = y + h;

    if (xmax > drm_p.drm_edp.fb_w)
        xmax = drm_p.drm_edp.fb_w;
    if (ymax > drm_p.drm_edp.fb_h)
        ymax = drm_p.drm_edp.fb_h;

    for(i = y; i < ymax; i++) 
	{
        uint8_t* row = (uint8_t*)drm_p.drm_edp.fb_vaddr + i * drm_p.drm_edp.fb_pitch;

        for (j = x; j < xmax; j++) 
		{
            uint8_t* pixel = row + j * 4;

			pixel[0] = b;
			pixel[1] = g;
			pixel[2] = r;
			pixel[3] = a;
        }
    }


	drmModeSetPlane(drm_p.drm_fd, 
					drm_p.drm_plane_id[1], 
					drm_p.drm_crtc_id[1], 
					drm_p.drm_edp.fb_id, 
					0,0,0,
					drm_p.drm_edp.fb_w, 
					drm_p.drm_edp.fb_h,
					0 << 16, 0 << 16, 
					drm_p.drm_edp.fb_w << 16,
					drm_p.drm_edp.fb_h << 16);


	return 0;
}


int lib_drm_hdmi_fill(uint32_t x, uint32_t y, uint32_t w,uint32_t h, uint32_t color)
{
	uint8_t a = 0;
	uint8_t r = 0;
	uint8_t g = 0;
	uint8_t b = 0;

	uint32_t i = 0;
	uint32_t j = 0;

	uint32_t xmax = x + w;
	uint32_t ymax = y + h;

    if (xmax > drm_p.drm_hdmi.fb_w)
        xmax = drm_p.drm_hdmi.fb_w;
    if (ymax > drm_p.drm_hdmi.fb_h)
        ymax = drm_p.drm_hdmi.fb_h;

    for(i = y; i < ymax; i++) 
	{
        uint8_t* row = (uint8_t*)drm_p.drm_hdmi.fb_vaddr + i * drm_p.drm_hdmi.fb_pitch;

        for (j = x; j < xmax; j++) 
		{
            uint8_t* pixel = row + j * 4;

			pixel[0] = b;
			pixel[1] = g;
			pixel[2] = r;
			pixel[3] = a;
        }
    }


	drmModeSetPlane(drm_p.drm_fd, 
					drm_p.drm_plane_id[0], 
					drm_p.drm_crtc_id[0], 
					drm_p.drm_hdmi.fb_id, 
					0,0,0,
					drm_p.drm_hdmi.fb_w, 
					drm_p.drm_hdmi.fb_h,
					0 << 16, 0 << 16, 
					drm_p.drm_hdmi.fb_w << 16,
					drm_p.drm_hdmi.fb_h << 16);


	return 0;
}


int lib_drm_get_edp_w(void)
{
	return drm_p.drm_edp.fb_w;
}

int lib_drm_get_edp_h(void)
{
	return drm_p.drm_edp.fb_h;
}

int lib_drm_get_hdmi_w(void)
{
	return drm_p.drm_hdmi.fb_w;
}

int lib_drm_get_hdmi_h(void)
{
	return drm_p.drm_hdmi.fb_h;
}

uint8_t * lib_drm_get_hdmi_addr(void)
{
	return drm_p.drm_hdmi.fb_vaddr;
}


int rkdrm_edp_display_video(MppFrame frame)
{
	int x = 0;
	int y = 0;
	int w = 0;
	int h = 0;
	int width  = 0;
	int height = 0;
	int swap_w = 0;
	int swap_h = 0;
	int size   = 0;

	long      us_start    = 0;
	long      us_end      = 0;
	//*******************************************************************
	
    int ret, fd, err;
	struct sp_bo *bo;
    uint32_t handles[4], pitches[4], offsets[4];
	MppFrameFormat frame_format;
	//*******************************************************************

	//*******************************************************************
    err = mpp_frame_get_errinfo(frame)|mpp_frame_get_discard(frame);
    if(err){
        log_n("get err info %d discard %d, go back.\n",
                mpp_frame_get_errinfo(frame),
                mpp_frame_get_discard(frame));
        return -1;
    }
	//*******************************************************************
    width  = mpp_frame_get_width(frame);
    height = mpp_frame_get_height(frame);
	
    width  = CODEC_ALIGN(width, 16);//16
    height = CODEC_ALIGN(height, 16);//16

	frame_format = mpp_frame_get_fmt(frame); //MPP_FMT_YUV420SP
	size         = mpp_buffer_get_size(mpp_frame_get_buffer(frame));
	fd           = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));
	//*******************************************************************
	
	swap_w = width;
	swap_h = height;

	log_n("swap_w =%d\n",swap_w);
	log_n("swap_h =%d\n",swap_h);
	//*******************************************************************

    bo = (struct sp_bo *)calloc(1, sizeof(struct sp_bo));
    if (!bo) {
        log_n("failed to calloc bo.\n");
        return -2;
    }

	//*******************************************************************

    drmPrimeFDToHandle(drm_p.drm_fd, fd, &bo->handle);
    bo->dev    = drm_p.drm_dev;
    bo->width  = swap_w;
    bo->height = swap_h;
    bo->depth  = 16;
    bo->bpp    = 32;
    bo->format = DRM_FORMAT_NV12;
    bo->flags  = 1;

    handles[0] = bo->handle;
    pitches[0] = swap_w;
    offsets[0] = 0;
    handles[1] = bo->handle;
    pitches[1] = swap_w;
    offsets[1] = swap_w * swap_h;
	
    ret = drmModeAddFB2(drm_p.drm_fd, bo->width, bo->height,
                        bo->format, handles, pitches, offsets,
                        &bo->fb_id, bo->flags);
    if (ret != 0) {
        log_e("failed to exec drmModeAddFb2.\n");
        return -3;
    }
	//*******************************************************************
	if(swap_w > swap_h)
	{
		w = lib_drm_get_edp_w();
		h = swap_h*lib_drm_get_edp_w()/swap_w;
		if(h > lib_drm_get_edp_h())
		{
			h = lib_drm_get_edp_h();
			w = swap_w*h/swap_h;
		}
		
		x = (lib_drm_get_edp_w() - w)/2;
		y = (lib_drm_get_edp_h() - h)/2;
	}
	else
	{
		h = lib_drm_get_edp_h();
		w = swap_w*lib_drm_get_edp_h()/swap_h;
		if(w > lib_drm_get_edp_w())
		{
			w = lib_drm_get_edp_w();
			h = swap_h*w/swap_w;
		}
				
		x = (lib_drm_get_edp_w() - w)/2;
		y = (lib_drm_get_edp_h() - h)/2;
	}

	log_n("x:y:w:h =%d:%d:%d:%d\n",x,y,w,h);
	//*******************************************************************

    ret = drmModeSetPlane(drm_p.drm_fd, drm_p.drm_edp_show->plane->plane_id,
                          drm_p.drm_dev->crtcs[1].crtc->crtc_id, bo->fb_id, 0,
                          x, y,   // display x, y
                          w, 	  //1920,//mCrtc->crtc->mode.hdisplay, // display width
                          h,      // 1080,//mCrtc->crtc->mode.vdisplay, // display height
                          0, 0, bo->width << 16, bo->height << 16);
    if (ret) {
        log_e("failed to exec drmModeSetPlane.\n");
        return -3;
    }
	//*******************************************************************

    if(drm_p.drm_edp_show->bo) 
	{
        if(drm_p.drm_edp_show->bo->fb_id)
		{
            ret = drmModeRmFB(drm_p.drm_fd, drm_p.drm_edp_show->bo->fb_id);
            if (ret)
                log_e("failed to exec drmModeRmFB.\n");
        }
		
        if(drm_p.drm_edp_show->bo->handle) 
		{
            struct drm_gem_close req = 
			{
				.handle = drm_p.drm_edp_show->bo->handle,
            };

            drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
        }
		
        free(drm_p.drm_edp_show->bo);
    }
    drm_p.drm_edp_show->bo = bo;
	//******************************************************************


    return 0;
}

int rkdrm_hdmi_display_video(MppFrame frame)
{
	int x = 0;
	int y = 0;
	int w = 0;
	int h = 0;
	int width  = 0;
	int height = 0;
	int swap_w = 0;
	int swap_h = 0;
	int size   = 0;

	long      us_start    = 0;
	long      us_end      = 0;
	//*******************************************************************
	
    int ret, fd, err;
	struct sp_bo *bo;
    uint32_t handles[4], pitches[4], offsets[4];
	MppFrameFormat frame_format;
	//*******************************************************************

	char * src_data = NULL;
	char * dst_data = NULL;
	
	MppBuffer dst_buffer = NULL;
	//*******************************************************************
    err = mpp_frame_get_errinfo(frame)|mpp_frame_get_discard(frame);
    if (err) {
        log_n("get err info %d discard %d, go back.\n",
                mpp_frame_get_errinfo(frame),
                mpp_frame_get_discard(frame));
        return -1;
    }

    width  = mpp_frame_get_width(frame);
    height = mpp_frame_get_height(frame);
	
    width  = CODEC_ALIGN(width, 16);//16
    height = CODEC_ALIGN(height, 16);//16

	swap_w = width;
	swap_h = height;

	frame_format = mpp_frame_get_fmt(frame); //MPP_FMT_YUV420SP
	size = mpp_buffer_get_size(mpp_frame_get_buffer(frame));
	//*******************************************************************

	#if 1
	mpp_buffer_get(NULL, &dst_buffer, size); //申请内存

	src_data = mpp_buffer_get_ptr(mpp_frame_get_buffer(frame));
	dst_data = mpp_buffer_get_ptr(dst_buffer);
	//*******************************************************************

	us_start = platform_get_microsecond();

	rga_nv12data_rotation(src_data,dst_data,swap_w,swap_h);

	us_end = platform_get_microsecond();
	
	//log_n("rotate time = %d\n",us_end - us_start);
	//***************************************************************

	swap_w = height;
	swap_h = width;

	log_n("swap_w=%d\n",swap_w);
	log_n("swap_h=%d\n",swap_h);
	//*******************************************************************


	fd = mpp_buffer_get_fd(dst_buffer);
	#else

	swap_w = width;
	swap_h = height;
	
	fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));

	#endif
	//*******************************************************************

    bo = (struct sp_bo *)calloc(1, sizeof(struct sp_bo));
    if (!bo) {
        log_n("failed to calloc bo.\n");
        return -2;
    }

	//*******************************************************************

    drmPrimeFDToHandle(drm_p.drm_fd, fd, &bo->handle);
    bo->dev    = drm_p.drm_dev;
    bo->width  = swap_w;
    bo->height = swap_h;
    bo->depth  = 16;
    bo->bpp    = 32;
    bo->format = DRM_FORMAT_NV12;
    bo->flags  = 1;

    handles[0] = bo->handle;
    pitches[0] = swap_w;
    offsets[0] = 0;
    handles[1] = bo->handle;
    pitches[1] = swap_w;
    offsets[1] = swap_w * swap_h;
	
    ret = drmModeAddFB2(drm_p.drm_fd, bo->width, bo->height,
                        bo->format, handles, pitches, offsets,
                        &bo->fb_id, bo->flags);
    if (ret != 0) {
        log_e("failed to exec drmModeAddFb2.\n");
        return -3;
    }
	//*******************************************************************
	if(swap_w > swap_h)
	{
		w = lib_drm_get_hdmi_w();
		h = swap_h*lib_drm_get_hdmi_w()/swap_w;
		if(h > lib_drm_get_hdmi_h())
		{
			h = lib_drm_get_hdmi_h();
			w = swap_w*h/swap_h;
		}
		
		x = (lib_drm_get_hdmi_w() - w)/2;
		y = (lib_drm_get_hdmi_h() - h)/2;
	}
	else
	{
		h = lib_drm_get_hdmi_h();
		w = swap_w*lib_drm_get_hdmi_h()/swap_h;
		if(w > lib_drm_get_hdmi_w())
		{
			w = lib_drm_get_hdmi_w();
			h = swap_h*w/swap_w;
		}
				
		x = (lib_drm_get_hdmi_w() - w)/2;
		y = (lib_drm_get_hdmi_h() - h)/2;
	}
	//*******************************************************************

    ret = drmModeSetPlane(drm_p.drm_fd, drm_p.drm_hdmi_show->plane->plane_id,
                          drm_p.drm_dev->crtcs[0].crtc->crtc_id, bo->fb_id, 0,
                          x, y,   // display x, y
                          w, 	  //1920,//mCrtc->crtc->mode.hdisplay, // display width
                          h,      // 1080,//mCrtc->crtc->mode.vdisplay, // display height
                          0, 0, bo->width << 16, bo->height << 16);
    if (ret) {
        log_e("failed to exec drmModeSetPlane.\n");
        return -3;
    }
	//*******************************************************************

    if(drm_p.drm_hdmi_show->bo) 
	{
        if(drm_p.drm_hdmi_show->bo->fb_id)
		{
            ret = drmModeRmFB(drm_p.drm_fd, drm_p.drm_hdmi_show->bo->fb_id);
            if (ret)
                log_e("failed to exec drmModeRmFB.\n");
        }
		
        if(drm_p.drm_hdmi_show->bo->handle) 
		{
            struct drm_gem_close req = 
			{
				.handle = drm_p.drm_hdmi_show->bo->handle,
            };

            drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
        }
		
        free(drm_p.drm_hdmi_show->bo);
    }
    drm_p.drm_hdmi_show->bo = bo;
	//*******************************************************************

	//******************************************************************
	if(dst_buffer){
		mpp_buffer_put(dst_buffer);
		dst_buffer = NULL;
	}
	//******************************************************************


    return 0;
}


int rkdrm_frame_display_video(void *packet_data,int packet_size,int packet_w,int packet_h)
{
	int x = 0;
	int y = 0;
	int w = 0;
	int h = 0;
	int width  = 0;
	int height = 0;
	int swap_w = 0;
	int swap_h = 0;
	int size   = 0;

	long      us_start    = 0;
	long      us_end      = 0;
	//*******************************************************************
	
    int ret, fd, err;
	struct sp_bo *bo;
    uint32_t handles[4], pitches[4], offsets[4];
	//*******************************************************************

	char * src_data = NULL;
	char * dst_data = NULL;
	
	MppBuffer dst_buffer = NULL;
	//*******************************************************************
	if(!packet_data){
		return -1;
	}
	
	if(!packet_size){
		return -1;
	}

	//*******************************************************************

    width  = packet_w;
    height = packet_h;
    width  = CODEC_ALIGN(width, 16);
    height = CODEC_ALIGN(height, 16);

	swap_w = width;
	swap_h = height;
	
	size   = packet_size;
	//*******************************************************************
	#if 1
	mpp_buffer_get(NULL, &dst_buffer, size); //申请内存

	src_data = mpp_buffer_get_ptr(packet_data);
	dst_data = mpp_buffer_get_ptr(dst_buffer);
	//*******************************************************************

	us_start = platform_get_microsecond();

	rga_nv12data_rotation(src_data,dst_data,swap_w,swap_h);

	us_end = platform_get_microsecond();
	
	//log_n("rotate time = %d\n",us_end - us_start);
	//***************************************************************

	swap_w = height;
	swap_h = width;
	//*******************************************************************


	fd = mpp_buffer_get_fd(dst_buffer);
	#else

	swap_w = width;
	swap_h = height;
	
	fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));

	#endif
	//*******************************************************************

    bo = (struct sp_bo *)calloc(1, sizeof(struct sp_bo));
    if (!bo) {
        log_n("failed to calloc bo.\n");
        return -2;
    }

	//*******************************************************************

    drmPrimeFDToHandle(drm_p.drm_fd, fd, &bo->handle);
    bo->dev    = drm_p.drm_dev;
    bo->width  = swap_w;
    bo->height = swap_h;
    bo->depth  = 16;
    bo->bpp    = 32;
    bo->format = DRM_FORMAT_NV12;
    bo->flags  = 1;

    handles[0] = bo->handle;
    pitches[0] = swap_w;
    offsets[0] = 0;
    handles[1] = bo->handle;
    pitches[1] = swap_w;
    offsets[1] = swap_w * swap_h;
	
    ret = drmModeAddFB2(drm_p.drm_fd, bo->width, bo->height,
                        bo->format, handles, pitches, offsets,
                        &bo->fb_id, bo->flags);
    if (ret != 0) {
        log_n("failed to exec drmModeAddFb2.\n");
        return -3;
    }
	//*******************************************************************
	if(swap_w > swap_h)
	{
		w = lib_drm_get_hdmi_w();
		h = swap_h*lib_drm_get_hdmi_w()/swap_w;
		if(h > lib_drm_get_hdmi_h())
		{
			h = lib_drm_get_hdmi_h();
			w = swap_w*h/swap_h;
		}
		
		x = (lib_drm_get_hdmi_w() - w)/2;
		y = (lib_drm_get_hdmi_h() - h)/2;
	}
	else
	{
		h = lib_drm_get_hdmi_h();
		w = swap_w*lib_drm_get_hdmi_h()/swap_h;
		if(w > lib_drm_get_hdmi_w())
		{
			w = lib_drm_get_hdmi_w();
			h = swap_h*w/swap_w;
		}
				
		x = (lib_drm_get_hdmi_w() - w)/2;
		y = (lib_drm_get_hdmi_h() - h)/2;
	}
	//*******************************************************************

    ret = drmModeSetPlane(drm_p.drm_fd, drm_p.drm_hdmi_show->plane->plane_id,
                          drm_p.drm_dev->crtcs->crtc->crtc_id, bo->fb_id, 0,
                          x, y,   // display x, y
                          w, 	  //1920,//mCrtc->crtc->mode.hdisplay, // display width
                          h,      // 1080,//mCrtc->crtc->mode.vdisplay, // display height
                          0, 0, bo->width << 16, bo->height << 16);
    if (ret) {
        log_n("failed to exec drmModeSetPlane.\n");
        return -3;
    }
	//*******************************************************************

    if(drm_p.drm_hdmi_show->bo) 
	{
        if(drm_p.drm_hdmi_show->bo->fb_id)
		{
            ret = drmModeRmFB(drm_p.drm_fd, drm_p.drm_hdmi_show->bo->fb_id);
            if (ret)
                log_n("failed to exec drmModeRmFB.\n");
        }
		
        if(drm_p.drm_hdmi_show->bo->handle) 
		{
            struct drm_gem_close req = 
			{
				.handle = drm_p.drm_hdmi_show->bo->handle,
            };

            drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
        }
		
        free(drm_p.drm_hdmi_show->bo);
    }
    drm_p.drm_hdmi_show->bo = bo;
	//*******************************************************************

	//******************************************************************
	if(dst_buffer){
		mpp_buffer_put(dst_buffer);
		dst_buffer = NULL;
	}
	//******************************************************************


    return 0;
}


int is_supported_format(struct sp_plane* plane, uint32_t format)
{
    uint32_t i;

    for (i = 0; i < plane->plane->count_formats; i++) {
        if (plane->plane->formats[i] == format)
            return 1;
    }
    return 0;
}

static int get_supported_format(struct sp_plane* plane, uint32_t* format)
{
    uint32_t i;

    for (i = 0; i < plane->plane->count_formats; i++) {
        if (plane->plane->formats[i] == DRM_FORMAT_XRGB8888 || plane->plane->formats[i] == DRM_FORMAT_ARGB8888 || plane->plane->formats[i] == DRM_FORMAT_RGBA8888) {
            *format = plane->plane->formats[i];
            return 0;
        }
    }
    printf("No suitable formats found!\n");
    return -ENOENT;
}


struct sp_plane* get_sp_plane(struct sp_dev *dev, struct sp_crtc *crtc) {
    int i;

    for (i = 0; i < dev->num_planes; i++) {
        struct sp_plane *p = &dev->planes[i];

        if (p->in_use)
            continue;

        if (!(p->plane->possible_crtcs & (1 << crtc->pipe)))
            continue;

        p->in_use = 1;
        return p;
    }
    return NULL;
}

static int   drm_new_frame     = 0;

void* lib_drm_show_thread(void *arg)
{
	int   ret = -1;
	int   packet_w  = 0;
	int   packet_h  = 0;
	int   packet_size = 0;
	int   packet_pts = 0;
	uint8_t * packet_data = NULL;

	while(1)
	{

		usleep(3000);

		if(ffmpeg_is_stop()){
			continue;
		}

		if(queue_frame_is_empty()){
			//log_n("frame empty\n");
			continue;
		}

#if 0
		if(!drm_new_frame)
		{
			log_n("03\n");
			ret = queue_frame_read(&packet_data,&packet_size,&packet_w,&packet_h,&packet_pts);
			if(ret!=0){
				continue;
			}

			drm_new_frame = 1;
		}

		f_p.f_v_clock = packet_pts * av_q2d(f_p.f_avformat->streams[f_p.f_v_index]->time_base);//s
		f_p.f_v_clock = f_p.f_v_clock*1000  - 120;//ms

		if(ffmpeg_sync_time_get() < f_p.f_v_clock)
		{
			continue;
		}

		log_n("packet_s=%d\n",packet_size);
		log_n("packet_w=%d\n",packet_w);
		log_n("packet_h=%d\n",packet_h);

		rkdrm_frame_display_video(packet_data,packet_size,packet_w,packet_h);

		log_n("05\n");

		queue_frame_free();
		
		drm_new_frame = 0;
#endif
	}

}


int lib_drm_init(void)
{
	int i = 0;
	int j = 0;
	int index = 0;
	int ret   = 0;

	memset(&drm_p,0,sizeof(drm_para_t));

	drmModeObjectProperties *props;
	drmModeAtomicReq *req;

	drm_p.drm_fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
	if(drm_p.drm_fd <= 0){
		log_e("open /dev/dri/card0 error\n");
		return -1;
	}
	drm_p.drm_res = drmModeGetResources(drm_p.drm_fd);
	if(!drm_p.drm_res){
		log_e("get drm res error\n");	
		close(drm_p.drm_fd);
		drm_p.drm_fd = 0;
		return -1;
	}

	log_n("fbs0_num=%d\n",drm_p.drm_res->count_fbs);
	log_n("crtc_num=%d\n",drm_p.drm_res->count_crtcs);
	log_n("conn_num=%d\n",drm_p.drm_res->count_connectors);	
	log_n("ende_num=%d\n",drm_p.drm_res->count_encoders);
	//*************************************************************
	for(i=0;i<drm_p.drm_res->count_crtcs;i++)
	{
		drm_p.drm_crtc_id[i] = drm_p.drm_res->crtcs[i];
		drm_p.drm_conn_id[i] = drm_p.drm_res->connectors[i];
	}
	//*************************************************************

	ret = drmSetClientCap(drm_p.drm_fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
	if(ret < 0){
		log_e("set client cap error.\n");
		close(drm_p.drm_fd);
		drm_p.drm_fd = 0;
		return -1;
	}
	//*************************************************************
	drm_p.drm_plane_res = drmModeGetPlaneResources(drm_p.drm_fd);
	if(!drm_p.drm_plane_res){
		log_e("get drm plane res error\n");	
		close(drm_p.drm_fd);
		drm_p.drm_fd = 0;
		return -1;
	}

	log_n("plane_num=%d\n",drm_p.drm_plane_res->count_planes);
	//*************************************************************

	for(i=0;i<drm_p.drm_plane_res->count_planes;i++)
	{
		drm_p.drm_plane_id[i] = drm_p.drm_plane_res->planes[i];
	}
	//*************************************************************
	for(i=0;i<drm_p.drm_res->count_crtcs;i++)
	{
		drm_p.drm_conn[i] = drmModeGetConnector(drm_p.drm_fd,drm_p.drm_conn_id[i]);

		log_n("h[%d]=%d\n",i,drm_p.drm_conn[i]->modes[0].hdisplay);
		log_n("v[%d]=%d\n",i,drm_p.drm_conn[i]->modes[0].vdisplay);
		log_n("c[%d]=%d\n",i,drm_p.drm_conn[i]->modes[0].clock);
		log_n("v[%d]=%d\n",i,drm_p.drm_conn[i]->modes[0].vrefresh);		
		log_n("n[%d]=%s\n",i,drm_p.drm_conn[i]->modes[0].name);

		drm_p.drm_buff[i].fb_w = drm_p.drm_conn[i]->modes[0].hdisplay;
		drm_p.drm_buff[i].fb_h = drm_p.drm_conn[i]->modes[0].vdisplay;

		log_n("fb_w[%d]=%d\n",i,drm_p.drm_buff[i].fb_w);
		log_n("fb_h[%d]=%d\n",i,drm_p.drm_buff[i].fb_h);
	}
	//********************************************************************************
	//create fb
	for(i=0;i<drm_p.drm_res->count_crtcs;i++)
	{

		drm_p.drm_buff[i].fb_create.width  = drm_p.drm_buff[i].fb_w;
		drm_p.drm_buff[i].fb_create.height = drm_p.drm_buff[i].fb_h;
		drm_p.drm_buff[i].fb_create.bpp	 = 32;

		/* handle, pitch, size will be returned */
		drmIoctl(drm_p.drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &drm_p.drm_buff[i].fb_create);

		/* bind the dumb-buffer to an FB object */
		drm_p.drm_buff[i].fb_pitch  = drm_p.drm_buff[i].fb_create.pitch;
		drm_p.drm_buff[i].fb_size   = drm_p.drm_buff[i].fb_create.size;
		drm_p.drm_buff[i].fb_hand   = drm_p.drm_buff[i].fb_create.handle;

		drmModeAddFB(drm_p.drm_fd, 
					 drm_p.drm_buff[i].fb_w, 
					 drm_p.drm_buff[i].fb_h, 
					 24, 32, 
					 drm_p.drm_buff[i].fb_pitch,
					 drm_p.drm_buff[i].fb_hand, 
					&drm_p.drm_buff[i].fb_id);

		log_n("pitch = %d\n",drm_p.drm_buff[i].fb_pitch);
		log_n("size  = %d\n",drm_p.drm_buff[i].fb_size);

		drm_p.drm_buff[i].fb_map.handle = drm_p.drm_buff[i].fb_create.handle;

		drmIoctl(drm_p.drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &drm_p.drm_buff[i].fb_map);

		drm_p.drm_buff[i].fb_vaddr = mmap(0,drm_p.drm_buff[i].fb_create.size, 
										  PROT_READ|PROT_WRITE,MAP_SHARED,
										  drm_p.drm_fd,drm_p.drm_buff[i].fb_map.offset);

		memset(drm_p.drm_buff[i].fb_vaddr,0,drm_p.drm_buff[i].fb_size);

		drmSetClientCap(drm_p.drm_fd, DRM_CLIENT_CAP_ATOMIC, 1);

		if(i == 0)
		{
			index = 1;
		}
		
		if(i == 1)
		{
			index = 0;
		}

		drmModeSetPlane(drm_p.drm_fd, 
					 	drm_p.drm_plane_id[index], 
						drm_p.drm_crtc_id[index], 
						drm_p.drm_buff[i].fb_id, 
						0,0,0,
						drm_p.drm_buff[i].fb_w, 
						drm_p.drm_buff[i].fb_h,
						0 << 16, 0 << 16, 
						drm_p.drm_buff[i].fb_w << 16,
						drm_p.drm_buff[i].fb_h << 16);


		if(i == 0)
		{
			log_n("edp pane\n");
			memcpy(&drm_p.drm_edp,&drm_p.drm_buff[i],sizeof(drm_device_fb));
		}
		
		if(i == 1)
		{
			log_n("hdmi pane\n");
			memcpy(&drm_p.drm_hdmi,&drm_p.drm_buff[i],sizeof(drm_device_fb));
		}
	}
	//********************************************************************************

	log_n("edp_w=%d\n",drm_p.drm_edp.fb_w);
	log_n("edp_h=%d\n",drm_p.drm_edp.fb_h);
	log_n("edp_p=%d\n",drm_p.drm_edp.fb_pitch);

	log_n("hdmi_w=%d\n",drm_p.drm_hdmi.fb_w);
	log_n("hdmi_h=%d\n",drm_p.drm_hdmi.fb_h);
	log_n("hdmi_p=%d\n",drm_p.drm_hdmi.fb_pitch);
	//********************************************************************************

	lib_drm_edp_fill(0,0,drm_p.drm_edp.fb_w,drm_p.drm_edp.fb_h,0);

	lib_drm_hdmi_fill(0,0,drm_p.drm_hdmi.fb_w,drm_p.drm_hdmi.fb_h,0);
	//********************************************************************************

	//********************************************************************************
	drm_p.drm_dev = (struct sp_dev*)calloc(1, sizeof(*drm_p.drm_dev));
    if (!drm_p.drm_dev) {
        log_e("failed to allocate dev\n");
        return -1;
    }

	 drm_p.drm_dev->fd = drm_p.drm_fd;

	 drm_p.drm_dev->num_connectors = drm_p.drm_res->count_connectors;
	 drm_p.drm_dev->connectors     = (drmModeConnectorPtr*)calloc(drm_p.drm_dev->num_connectors, sizeof(*drm_p.drm_dev->connectors));
	 if(!drm_p.drm_dev->connectors) 
	 {
		 log_e("failed to allocate connectors\n");
		 return -1;
	 }
	 for(i = 0; i < drm_p.drm_dev->num_connectors; i++)
	 {
		 drm_p.drm_dev->conn_id[i] = drm_p.drm_res->connectors[i];
	 
		 drm_p.drm_dev->connectors[i] = drmModeGetConnector(drm_p.drm_dev->fd,drm_p.drm_res->connectors[i]);
		 if (!drm_p.drm_dev->connectors[i]) {
			 log_e("failed to get connector %d\n", i);
			 return -1;
		 }
		 
		 log_n("hdisplay[%d] = %d\n",i,drm_p.drm_dev->connectors[i]->modes[0].hdisplay);
		 log_n("vdisplay[%d] = %d\n",i,drm_p.drm_dev->connectors[i]->modes[0].vdisplay); 
	 }
	 //****************************************************************************************************
	 drm_p.drm_dev->num_encoders = drm_p.drm_res->count_encoders;
	 drm_p.drm_dev->encoders = (drmModeEncoderPtr*)calloc(drm_p.drm_dev->num_encoders, sizeof(*drm_p.drm_dev->encoders));
	 if(!drm_p.drm_dev->encoders) 
	 {
		 log_e("failed to allocate encoders\n");
		 return -1;
	 }
	 for(i = 0; i < drm_p.drm_dev->num_encoders; i++) 
	 {
		 drm_p.drm_dev->encoders[i] = drmModeGetEncoder(drm_p.drm_dev->fd, drm_p.drm_res->encoders[i]);
		 if (!drm_p.drm_dev->encoders[i]) {
			 log_e("failed to get encoder %d\n", i);
			 return -1;
		 }
	 }
	 //****************************************************************************************************
	 drm_p.drm_dev->num_crtcs = drm_p.drm_res->count_crtcs;
	 drm_p.drm_dev->crtcs     = (struct sp_crtc*)calloc(drm_p.drm_dev->num_crtcs, sizeof(struct sp_crtc));
	 if(!drm_p.drm_dev->crtcs) 
	 {
		 log_e("failed to allocate crtcs\n");
		 return -1;
	 }
	 
	 log_i("num_crtcs=%d\n", drm_p.drm_dev->num_crtcs);
	 
	 for (i = 0; i < drm_p.drm_dev->num_crtcs; i++) 
	 {
		 drm_p.drm_dev->crtc_id[i] = drm_p.drm_res->crtcs[i];
	 
		 drm_p.drm_dev->crtcs[i].crtc = drmModeGetCrtc(drm_p.drm_dev->fd, drm_p.drm_res->crtcs[i]);
		 if (!drm_p.drm_dev->crtcs[i].crtc) {
			 log_e("failed to get crtc %d\n", i);
			 return -1;
		 }
		 drm_p.drm_dev->crtcs[i].scanout = NULL;
		 drm_p.drm_dev->crtcs[i].pipe = i;
		 drm_p.drm_dev->crtcs[i].num_planes = 0;
	 }
	 //****************************************************************************************************
	 drmModePlaneRes* pr = NULL;
	 
	 pr = drmModeGetPlaneResources(drm_p.drm_dev->fd);
	 if(!pr){
		 log_e("failed to get plane resources\n");
		 return -1;
	 }
	 
	 drm_p.drm_dev->num_planes = pr->count_planes;
	 drm_p.drm_dev->planes = (struct sp_plane*)calloc(drm_p.drm_dev->num_planes, sizeof(struct sp_plane));
	 for(i = 0; i < drm_p.drm_dev->num_planes; i++) 
	 {
		 //drmModeObjectPropertiesPtr props;
		 struct sp_plane* plane = &drm_p.drm_dev->planes[i];
	 
		 plane->dev = drm_p.drm_dev;
		 plane->plane = drmModeGetPlane(drm_p.drm_dev->fd, pr->planes[i]);
		 if (!plane->plane) {
			 log_e("failed to get plane %d\n", i);
			 return -1;
		 }
		 plane->bo = NULL;
		 plane->in_use = 0;
	 
		 ret = get_supported_format(plane, &plane->format);
		 if (ret) {
			 log_e("failed to get supported format: %d\n", ret);
			 return -1;
		 }
	 
		 for (j = 0; j < drm_p.drm_dev->num_crtcs; j++) {
			 if (plane->plane->possible_crtcs & (1 << j))
				 drm_p.drm_dev->crtcs[j].num_planes++;
		}
	}
	//****************************************************************************************************
	//get hdmi nv12 format

	drm_p.drm_hdmi_plane = (struct sp_plane **)calloc(drm_p.drm_dev->num_planes, sizeof(*drm_p.drm_hdmi_plane));
	if(!drm_p.drm_hdmi_plane){
		log_n("failed to calloc mPlanes.\n");
		return -3;
	}	 

	drm_p.drm_hdmi_Crtc = &drm_p.drm_dev->crtcs[0];
	log_n("num_planes=%d\n",drm_p.drm_dev->num_planes);

    for(i = 0; i < drm_p.drm_dev->num_planes; i++) 
	{
		drm_p.drm_hdmi_plane[i] = get_sp_plane(drm_p.drm_dev, drm_p.drm_hdmi_Crtc);
		if(drm_p.drm_hdmi_plane[i])
		{
			if (is_supported_format(drm_p.drm_hdmi_plane[i], DRM_FORMAT_NV12))
			{
				drm_p.drm_hdmi_show = drm_p.drm_hdmi_plane[i];
				log_i("hdmi get nv12 format plane\n");
			}
		}
    }	 
	//****************************************************************************************************
	//get edpv12 format

	drm_p.drm_edp_plane = (struct sp_plane **)calloc(drm_p.drm_dev->num_planes, sizeof(*drm_p.drm_edp_plane));
	if(!drm_p.drm_edp_plane){
		log_n("failed to calloc mPlanes.\n");
		return -3;
	}	 

	drm_p.drm_edp_Crtc = &drm_p.drm_dev->crtcs[1];
	
	log_i("num_planes=%d\n",drm_p.drm_dev->num_planes);

    for(i = 0; i < drm_p.drm_dev->num_planes; i++) 
	{
		drm_p.drm_edp_plane[i] = get_sp_plane(drm_p.drm_dev, drm_p.drm_edp_Crtc);
		if(drm_p.drm_edp_plane[i])
		{
			if(is_supported_format(drm_p.drm_edp_plane[i], DRM_FORMAT_NV12))
			{
				drm_p.drm_edp_show = drm_p.drm_edp_plane[i];
				log_i("edp get nv12 format plane\n");
			}
		}
    }	
	//****************************************************************************************************

	ret=pthread_create(&drm_p.drm_thread,NULL,lib_drm_show_thread,NULL);
	if(ret != 0){
		log_e("error=%s\n",strerror(ret));
	}
	//****************************************************************************************************


	return 0;
}

int lib_drm_exit(void)
{

#if 0
	drm_destroy_fb(&buf);
	drm_destroy_fb(&buf2);
	
	drmModeFreeConnector(conn);
	drmModeFreeConnector(conn2);
	drmModeFreePlaneResources(plane_res);
	drmModeFreeResources(res);
	close(fd);
#endif
}



